package com.ct.application.sysrole.service.impl;

import com.ct.application.commons.vo.StatusRequest;
import com.ct.application.sysapis.model.vo.SysApisVO;
import com.ct.application.sysrmenus.model.vo.SysMenusVO;
import com.ct.application.sysrole.model.vo.SysRolesMenuApisVO;
import com.ct.application.sysrole.model.vo.SysRolesVO;
import com.ct.application.sysrole.request.*;
import com.ct.application.sysrole.service.ISysRolesService;
import com.ct.application.sysuser.contants.SysUserContants;
import com.ct.rbac.enums.RbacResultEnum;
import com.ct.rbac.model.SysApisModel;
import com.ct.rbac.model.SysMenusModel;
import com.ct.rbac.model.SysRoleModel;
import com.ct.rbac.orm.SysRolesDO;
import com.ct.rbac.repository.*;
import com.ct.redis.util.RedisUtil;
import com.ct.repository.commons.PageUtils;
import com.ct.repository.convert.CopyConvertUtils;
import com.ct.utils.JsonUtil;
import com.ct.utils.exception.ApiException;
import com.ct.utils.jwt.JwtUtil;
import com.ct.utils.result.StatusEnums;
import com.ct.utils.threadlocal.UserThreadLocal;
import com.ct.utils.valid.ValidatorUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author Auto Generator
 * @since 2023-08-13
 */
@Service
public class SysRolesServiceImpl implements ISysRolesService {
    @Resource
    private ISysMenusRespontory sysMenusRespontory;
    @Resource
    private ISysApisRespontory sysApisRespontory;
    @Resource
    private ISysRolesRespontory sysRolesRespontory;
    @Resource
    private ISysUserRolesRespontory sysRoleRolesRespontory;
    @Resource
    private ISysRoleMenusRespontory sysRoleMenusRespontory;
    @Resource
    private ISysRoleApisRespontory sysRoleApisRespontory;
    @Resource
    private RedisUtil<String> redisUtil;

    /**
     * 分页查询角色列表
     *
     * @param sysRoleSearchRequest
     * @return
     */
    @Override
    public PageUtils<SysRolesVO> findSystemPage(SysRoleSearchRequest sysRoleSearchRequest) {
        PageUtils<SysRoleModel> respontoryRoles = sysRolesRespontory.findPageSystem(sysRoleSearchRequest.getPageNo(),
                sysRoleSearchRequest.getPageSize(), sysRoleSearchRequest.getStatus(), sysRoleSearchRequest.getKeyword());
        PageUtils<SysRolesVO> sysRolesVOPageUtils = tranferPageUtilsBo(respontoryRoles, SysRolesVO.class);
        List<SysRolesVO> records = sysRolesVOPageUtils.getRecords();
        if (sysRoleSearchRequest.getUserId() != null && !CollectionUtils.isEmpty(records)) {
            // 用户已经绑定的角色
            List<Long> userRoleIds = sysRoleRolesRespontory.findUserRoleIds(sysRoleSearchRequest.getUserId());
            if (!CollectionUtils.isEmpty(userRoleIds)) {
                List<SysRolesVO> collect = records.stream().map(c -> {
                    // 当前的角色是不是已经在用户绑定的列表中，如果在就返回1，。不在就返回0
                    long count = userRoleIds.stream().filter(roleId -> roleId.equals(c.getId())).count();
                    c.setBindFlag(count > 0);
                    return c;
                }).collect(Collectors.toList());
                sysRolesVOPageUtils.setRecords(collect);
            }
        }
        return sysRolesVOPageUtils;
    }
    /**
     * 分页查询角色列表
     *
     * @param sysRoleSearchRequest
     * @return
     */
    @Override
    public PageUtils<SysRolesVO> findPage(SysRoleSearchRequest sysRoleSearchRequest) {
        PageUtils<SysRoleModel> respontoryRoles = sysRolesRespontory.findPage(sysRoleSearchRequest.getPageNo(),
                sysRoleSearchRequest.getPageSize(), sysRoleSearchRequest.getStatus(), sysRoleSearchRequest.getKeyword());
        PageUtils<SysRolesVO> sysRolesVOPageUtils = tranferPageUtilsBo(respontoryRoles, SysRolesVO.class);
        List<SysRolesVO> records = sysRolesVOPageUtils.getRecords();
        if (sysRoleSearchRequest.getUserId() != null && !CollectionUtils.isEmpty(records)) {
            // 用户已经绑定的角色
            List<Long> userRoleIds = sysRoleRolesRespontory.findUserRoleIds(sysRoleSearchRequest.getUserId());
            if (!CollectionUtils.isEmpty(userRoleIds)) {
                List<SysRolesVO> collect = records.stream().map(c -> {
                    // 当前的角色是不是已经在用户绑定的列表中，如果在就返回1，。不在就返回0
                    long count = userRoleIds.stream().filter(roleId -> roleId.equals(c.getId())).count();
                    c.setBindFlag(count > 0);
                    return c;
                }).collect(Collectors.toList());
                sysRolesVOPageUtils.setRecords(collect);
            }
        }
        return sysRolesVOPageUtils;
    }

    /**
     * 根据角色id查询对应的菜单和权限apis信息
     *
     * @param roleId
     * @return
     */
    @Override
    public SysRolesMenuApisVO findRoleMenusPermission(Long roleId) {
        List<SysMenusModel> menuList = sysMenusRespontory.findSysMenusList(roleId);
        List<SysApisModel> apisList = sysApisRespontory.findRoleApis(roleId);
        SysRolesMenuApisVO vo = new SysRolesMenuApisVO();
        if (CollectionUtils.isEmpty(menuList)) {
            menuList = new ArrayList<>();
        }
        if (CollectionUtils.isEmpty(apisList)) {
            apisList = new ArrayList<>();
        }
        vo.setMenus(menuList);
        vo.setPermissions(apisList);
        // 把当前角色对应的权限放入到redis，方便后续的拦截器进行控制和使用
        redisUtil.set(SysUserContants.RBAC_PERMISSION_LIST + UserThreadLocal.get().getId(), JsonUtil.obj2String(apisList), JwtUtil.EXPIRE_TIME, TimeUnit.MILLISECONDS);
        return vo;
    }


    /**
     * 根据角色id查询对应的菜单
     *
     * @param roleId
     * @return
     */
    @Override
    public List<SysMenusVO> findRoleMenus(Long roleId) {
        List<SysMenusModel> menuList = sysMenusRespontory.findSysMenusList(roleId);
        // 把当前角色对应的权限放入到redis，方便后续的拦截器进行控制和使用
        return tranferListBo(menuList,SysMenusVO.class);
    }

    /**
     * 根据角色id查询对应的权限
     *
     * @param roleId
     * @return
     */
    @Override
    public List<SysApisVO> findRoleApis(Long roleId) {
        List<SysApisModel> apisList = sysApisRespontory.findRoleApis(roleId);
        // 把当前角色对应的权限放入到redis，方便后续的拦截器进行控制和使用
        return tranferListBo(apisList,SysApisVO.class);
    }


    @Override
    public SysRolesVO selectById(Long id) {
        SysRolesDO sysRolesDO = sysRolesRespontory.getById(id);
        return tranferBo(sysRolesDO,SysRolesVO.class);
    }

    @Override
    public Boolean deleteById(Long id) {
        // 如果角色被用户绑定了。直接返回
        if(sysRoleRolesRespontory.countBindRoleUser(id)){
            throw new ApiException(RbacResultEnum.ROLE_YINYONG_API_EX);
        }
        // 如果角色被菜单绑定了。直接返回
        if(sysRoleMenusRespontory.countRoleMenu(id)){
            throw new ApiException(RbacResultEnum.ROLE_MENU_YINYONG_API_EX);
        }
        // 如果角色被权限绑定了。直接返回
        if(sysRoleApisRespontory.countRoleApi(id)){
            throw new ApiException(RbacResultEnum.ROLE_API_YINYONG_API_EX);
        }

        return sysRolesRespontory.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysRolesVO saveSysRoles(SysRoleSaveRequest sysRoleSaveRequest) {
        SysRolesDO sysRolesDO = CopyConvertUtils.copyProperties(sysRoleSaveRequest, SysRolesDO.class);
        boolean b = sysRolesRespontory.save(sysRolesDO);
        if (b){
            return CopyConvertUtils.copyProperties(sysRolesDO, SysRolesVO.class);
        }
        return null;
    }

    @Override
    public SysRolesVO updateSysRoles(SysRoleUpdateRequest sysRoleUpdateRequest) {
        SysRolesDO sysRolesDO = CopyConvertUtils.copyProperties(sysRoleUpdateRequest, SysRolesDO.class);
        boolean b = sysRolesRespontory.updateById(sysRolesDO);
        if (b){
            return CopyConvertUtils.copyProperties(sysRolesDO, SysRolesVO.class);
        }
        return null;
    }

    @Override
    public Boolean updateStatusSysRoles(StatusRequest statusRequest) {
        if(ValidatorUtil.isNumeric(statusRequest.getValue())) {
            return sysRolesRespontory.updateStatus(statusRequest.getId(), statusRequest.getField(), Integer.parseInt(statusRequest.getValue()));
        }else{
            return sysRolesRespontory.updateStatusStr(statusRequest.getId(), statusRequest.getField(), statusRequest.getValue());
        }
    }

    @Override
    public Boolean batchStatus(SysRoleBatchRequest sysRoleBatchRequest) {
        List<Long> userIds = sysRoleBatchRequest.getIds();
        List<SysRolesDO> sysRolesDOS = userIds.stream().map(userId -> {
            SysRolesDO sysRolesDO = new SysRolesDO();
            sysRolesDO.setId(userId);
            sysRolesDO.setStatus(StatusEnums.STATUS.getCode());
            return sysRolesDO;
        }).collect(Collectors.toList());
        return sysRolesRespontory.updateBatchById(sysRolesDOS);
    }

    @Override
    public Boolean batchForbiddens(SysRoleBatchRequest sysRoleBatchRequest) {
        List<Long> userIds = sysRoleBatchRequest.getIds();
        List<SysRolesDO> sysRolesDOS = userIds.stream().map(userId -> {
            SysRolesDO sysRolesDO = new SysRolesDO();
            sysRolesDO.setId(userId);
            sysRolesDO.setStatus(StatusEnums.UN_STATUS.getCode());
            return sysRolesDO;
        }).collect(Collectors.toList());
        return sysRolesRespontory.updateBatchById(sysRolesDOS);
    }

    @Override
    public Boolean bindMenus(SysRoleBindMenuRequest sysRoleBindMenuRequest) {
        return sysRoleMenusRespontory.bindMenus(sysRoleBindMenuRequest.getRoleId(),sysRoleBindMenuRequest.getMenusIds());
    }

    @Override
    public Boolean bindApis(SysRoleBindApisRequest sysRoleBindApisRequest) {
        return sysRoleApisRespontory.bindApis(sysRoleBindApisRequest.getRoleId(),sysRoleBindApisRequest.getApisId());
    }
}
